package partner

import (
	. "chess_platform/internal/common"
	"chess_platform/models/pb"
	"errors"
	"fmt"
	"github.com/astaxie/beego/orm"
	"strings"
	"time"
)

func NewUser(user map[string]interface{}, multiOrm ...orm.Ormer) (int64, error) {
	o := NewOrm(multiOrm, DBChessPartner)
	values, sql := InsertSql(TablePfUser, user)
	result, err := o.Raw(sql, values).Exec()
	if err != nil {
		return 0, err
	}
	return result.LastInsertId()
}

func UpdateUser(user map[string]interface{}, uid int64, multiOrm ...orm.Ormer) (int64, error) {
	o := NewOrm(multiOrm, DBChessPartner)
	condition := fmt.Sprintf(`uid = %v`, uid)
	values, sql := UpdateSql(TablePfUser, user, condition)
	result, err := o.Raw(sql, values).Exec()
	if err != nil {
		return 0, err
	}
	return result.RowsAffected()
}

//更新总代名下所有代理的信息
func UpdateUserByRootId(user map[string]interface{}, rootId int64, multiOrm ...orm.Ormer) (int64, error) {
	o := NewOrm(multiOrm, DBChessPartner)
	condition := fmt.Sprintf(`root_id = %v`, rootId)
	values, sql := UpdateSql(TablePfUser, user, condition)
	result, err := o.Raw(sql, values).Exec()
	if err != nil {
		return 0, err
	}
	return result.RowsAffected()
}

//更新一级代理的开通代理的名额
func UpdateUserAgentNum(agentNum, uid int64, multiOrm ...orm.Ormer) (int64, error) {
	o := NewOrm(multiOrm, DBChessPartner)
	sql := fmt.Sprintf(`UPDATE %v SET agent_num = agent_num + %v WHERE uid = %v`, TablePfUser, agentNum, uid)
	result, err := o.Raw(sql).Exec()
	if err != nil {
		return 0, err
	}
	return result.RowsAffected()
}

var ErrNoBonusRate = errors.New(fmt.Sprintf("您的提成比例不足以开通下级代理,请联系上级调整"))
var ErrNoAgentNum = errors.New(fmt.Sprintf("您的代理名额不足,请联系客服"))
var ErrAlreadyAgent = errors.New(fmt.Sprintf("此玩家已是代理"))

//代理(合伙人不行)指定玩家成为代理,直接在partner_user表里生成一条记录，同时记录group_id,root_id, pid,union_id
func Player2Agent(playerId, agentId int64) error {
	/*
		0. 判断此玩家是否已经是代理了
		1. 先在玩家passport表里找到此playerId的union_id
		2. 在partner_user里新建一条记录,要记录group_id,root_id,pid,level,union_id, status置为0
		3. 在登录时通过union_id去搜索,然后把open_id填上
	*/
	sql := fmt.Sprintf(`
		SELECT
			uid
		FROM
			%v
		WHERE
			uid = %v
		LIMIT 1
	`, TablePfUser, playerId)
	op := NewDBOrm(DBChessPartner)
	var uid int64
	op.Raw(sql).QueryRow(&uid)
	if uid == playerId {
		return ErrAlreadyAgent
	}

	type Agent struct {
		GroupId   int64 `json:"group_id"`
		RootId    int64 `json:"root_id"`
		Level     int64 `json:"level"`
		BonusRate int64 `json:"bonus_rate"`
		AgentNum  int64 `json:"agent_num"`
	}
	var agent Agent
	//找出代理的group_id,root_id,pid,union_id,status
	sql = fmt.Sprintf(`
		SELECT
			group_id,root_id,level,agent_num
		FROM
			%v
		WHERE
			uid = %v
	`, TablePfUser, agentId)
	err := op.Raw(sql).QueryRow(&agent)
	if err != nil {
		return err
	}
	if agent.AgentNum < 1 {
		return ErrNoAgentNum
	}
	//找出union_id
	sql = fmt.Sprintf(`
		SELECT
			union_id,open_id
		FROM
			%v
		WHERE
			uid = %v
	`, TableClientPassport, playerId)
	oc := NewDBOrm(DBChess)
	var unionId, openId string
	err = oc.Raw(sql).QueryRow(&unionId, &openId)
	if err != nil {
		return err
	}

	//找出玩家的头像及名字
	sql = fmt.Sprintf(`
		SELECT
			nickname,imageurl
		FROM
			%v
		WHERE
			uid = %v
	`, TableClientUser, playerId)
	var nickname, imageUrl string
	oc.Raw(sql).QueryRow(&nickname, &imageUrl)

	data := map[string]interface{}{
		"uid":          playerId,
		"pid":          agentId,
		"level":        agent.Level + 1,
		"group_id":     agent.GroupId,
		"root_id":      agent.RootId,
		"bonus_rate":   0,
		"union_id":     unionId,
		"open_id":      openId,
		"nickname":     nickname,
		"head_img_url": imageUrl,
	}
	_, err = NewUser(data, op)
	if err != nil {
		return err
	}

	//减少代理的名额
	_, err = UpdateUserAgentNum(-1, agentId)
	if err != nil {
		return err
	}
	return nil
}

func UpdateUserByCondition(user map[string]interface{}, condition string, multiOrm ...orm.Ormer) (int64, error) {
	o := NewOrm(multiOrm, DBChessPartner)
	values, sql := UpdateSql(TablePfUser, user, condition)
	result, err := o.Raw(sql, values).Exec()
	if err != nil {
		return 0, err
	}
	return result.RowsAffected()
}

//新增代理登录日志
func NewLoginLog(data map[string]interface{}) (int64, error) {
	o := NewDBOrm(DBChessPartner)
	values, sql := InsertSql(TablePfLoginLog, data)
	result, err := o.Raw(sql, values).Exec()
	if err != nil {
		return 0, err
	}
	return result.LastInsertId()
}

//24小时没处理申请自动变为拒绝
//true--未到24小时
//false--已到24小时
func HandleAgentStatus(createTime, uid, pid, groupId int64, isRegisterStatus bool) (bool, error) {
	if isRegisterStatus && time.Now().Unix()-createTime >= 86400 { //如果仅仅是注册成功就没有24小时自动拒绝概念
		user := map[string]interface{}{
			"create_time": time.Now().Unix(), //超过了24小时，就把注册成功改为现在
		}
		_, err := UpdateUser(user, uid)
		if err != nil {
			return true, err
		}
		return true, nil
	}
	if time.Now().Unix()-createTime >= 86400 { //超过24小时86400 = 24 * 3600
		user := map[string]interface{}{
			"status": VerifyNotPass,
		}
		if pid != 0 { //开通非总代
			o := NewDBOrm(DBChessPartner)
			o.Begin()
			defer o.Rollback()
			//更新被审核的代理状态
			_, err := UpdateUser(user, uid, o)
			if err != nil {
				o.Rollback()
				return true, err
			}
			//如果审核失败，就还原一个开通代理的名额
			//更新上级代理数加1
			_, err = UpdateUserAgentNum(1, pid, o)
			if err != nil {
				o.Rollback()
				return true, err
			}
			o.Commit()
			return false, nil
		} else { //开通总代
			_, err := UpdateUser(user, uid)
			if err != nil {
				return true, err
			}
			//如果审核失败，就还原合伙人开通总代的一个名额
			//更新上级代理数加1
			_, err = pb.UpdateUserAgentNum(1, groupId)
			if err != nil {
				return true, err
			}

			return false, nil
		}
	}
	return true, nil
}

//统计代理有多少下级代理(去除审核不通过的)
func CountLevel2AgentNum(uid int64, multiOrm ...orm.Ormer) (int64, error) {
	sql := fmt.Sprintf(`
		SELECT
			COUNT(1)
		FROM
			%v
		WHERE
			pid = ? AND status != ?
		LIMIT 1
		`, TablePfUser)
	o := NewOrm(multiOrm, DBChessPartner)
	var count int64
	err := o.Raw(sql, uid, VerifyNotPass).QueryRow(&count)
	if CheckError(err) {
		return 0, err
	}
	return count, nil
}

func UserInfoByTelephone(telephone string, multiOrm ...orm.Ormer) (PartnerUser, error) {
	sql := fmt.Sprintf(`
		SELECT
			uid,level,phone,status,password,login_time,frozen,frozen_reason
		FROM
			%v
		WHERE
			phone = ?
		LIMIT 1
		`, TablePfUser)
	o := NewOrm(multiOrm, DBChessPartner)
	var user PartnerUser
	err := o.Raw(sql, telephone).QueryRow(&user)
	if CheckNoExist(err) {
		return user, nil
	}
	return user, err
}

func SpecifyUserInfoById(uid int64, field []string, multiOrm ...orm.Ormer) (*PartnerUser, error) {
	fieldStr := strings.Join(field, ",")
	sql := fmt.Sprintf(`
		SELECT
			%v
		FROM
			%v
		WHERE
			uid = ?
		LIMIT 1
		`, fieldStr, TablePfUser)
	o := NewOrm(multiOrm, DBChessPartner)
	var user PartnerUser
	err := o.Raw(sql, uid).QueryRow(&user)
	if CheckNoExist(err) {
		return nil, nil
	}
	return &user, err
}

//获取下级代理
func ListLevelUser(p ListParams, uid int64, multiOrm ...orm.Ormer) ([]orm.Params, int64, error) {
	o := NewOrm(multiOrm, DBChessPartner)
	limit := (p.PageIndex - 1) * p.PageSize
	where := fmt.Sprintf(" pid = %v AND status = %v", uid, FirstTopUpSuccess)
	sql := fmt.Sprintf(`
		SELECT
			uid,level,nickname,remark,status,head_img_url,phone,bonus_rate,create_time
		FROM
			%v
		WHERE
			%v
		LIMIT ?,?
	`, TablePfUser, where)
	var user []orm.Params
	_, err := o.Raw(sql, limit, p.PageSize).Values(&user)
	if CheckNoExist(err) {
		return user, 0, nil
	}
	oc := NewDBOrm(DBChess)
	for _, v := range user {
		v["player_count"] = CountAgentPlayer(v["uid"], oc)
		v["next_agent_count"] = CountNextLevelAgent(v["uid"], o)
		v["consume_card"] = PlayerConsumeCard(v["uid"], oc)
	}

	sql = fmt.Sprintf(`SELECT COUNT(1) FROM %v WHERE %v`, TablePfUser, where)
	var count int64
	o.Raw(sql).QueryRow(&count)
	return user, count, err
}

//合伙人系统下的玩家玩游戏消耗的钻石数量
func PlayerConsumeCard(uid interface{}, multiOrm ...orm.Ormer) int64 {
	var consumeCard int64
	o := NewOrm(multiOrm, DBChess)
	sql := fmt.Sprintf(`
		SELECT
			consume_card
		FROM
			%v
		WHERE
			uid = %v
		`, TableClientUserAttr, uid)
	o.Raw(sql).QueryRow(&consumeCard)
	return consumeCard
}

//代理今日充值
func AgentTodayCharge(uid interface{}, multiOrm ...orm.Ormer) int64 {
	var todayCharge int64 //今日收入
	o := NewOrm(multiOrm, DBChessPartner)
	start, end := GetTodayTimestamp()
	//今日充值
	sql := fmt.Sprintf(`
		SELECT
			IF(SUM(cash) is NULL,0,SUM(cash)) AS today_charge
		FROM
			%v
		WHERE
			agent_id = %v AND type = %v AND create_time >= %v AND create_time < %v
		`, TablePfCashRecord, uid, PfCashAgentCharge, start, end)
	o.Raw(sql).QueryRow(&todayCharge)
	return todayCharge
}

func AgentTotalCharge(uid interface{}, multiOrm ...orm.Ormer) int64 {
	var totalCharge int64
	o := NewOrm(multiOrm, DBChessPartner)
	//总充值
	sql := fmt.Sprintf(`
		SELECT
			IF(SUM(cash) is NULL,0,SUM(cash)) AS total_charge
		FROM
			%v
		WHERE
			agent_id = %v AND type = %v
		`, TablePfCashRecord, uid, PfCashAgentCharge)
	o.Raw(sql).QueryRow(&totalCharge)
	return totalCharge
}

//计算下一级代理的个数
func CountNextLevelAgent(agentId interface{}, multiOrm ...orm.Ormer) int64 {
	sql := fmt.Sprintf(`
		SELECT
			COUNT(1)
		FROM
			%v
		WHERE
			pid = %v AND status = %v
	`, TablePfUser, agentId, FirstTopUpSuccess)
	var count int64
	o := NewOrm(multiOrm, DBChessPartner)
	o.Raw(sql).QueryRow(&count)
	return count
}

//今天直属代理的个数
func TodayAgent(agentId interface{}, multiOrm ...orm.Ormer) int64 {
	var todayAgent int64
	start, end := GetTodayTimestamp()
	sql := fmt.Sprintf(`
		SELECT
			COUNT(1) AS today_agent
		FROM
			%v
		WHERE
			pid = %v AND status = %v AND create_time >= %v AND create_time < %v
		`, TablePfUser, agentId, PfFirstTopUpSuccess, start, end)
	o := NewOrm(multiOrm, DBChessPartner)
	o.Raw(sql).QueryRow(&todayAgent)
	return todayAgent
}

//计算总代名下所有代理总数
func CountRootAllAgent(rootId interface{}, multiOrm ...orm.Ormer) int64 {
	sql := fmt.Sprintf(`
		SELECT
			COUNT(1)
		FROM
			%v
		WHERE
			root_id = %v AND status = %v
	`, TablePfUser, rootId, FirstTopUpSuccess)
	var count int64
	o := NewOrm(multiOrm, DBChessPartner)
	o.Raw(sql).QueryRow(&count)
	return count
}

//计算合伙人下总代代理的个数
func CountRootAgent(GroupId interface{}, multiOrm ...orm.Ormer) int64 {
	sql := fmt.Sprintf(`
		SELECT
			COUNT(1)
		FROM
			%v
		WHERE
			pid = 0 AND group_id = %v AND status = %v
	`, TablePfUser, GroupId, FirstTopUpSuccess)
	var count int64
	o := NewOrm(multiOrm, DBChessPartner)
	o.Raw(sql).QueryRow(&count)
	return count
}

//计算代理名下直属的玩家数
func CountAgentPlayer(agentId interface{}, multiOrm ...orm.Ormer) int64 {
	sql := fmt.Sprintf(`
		SELECT
			COUNT(1)
		FROM
			%v
		WHERE
			agent_uid = %v AND player_uid != 0
	`, TableAgentPlayer, agentId)
	var count int64
	o := NewOrm(multiOrm, DBChess)
	o.Raw(sql).QueryRow(&count)
	return count
}

//计算代理名下直属的总玩家数
func TodayAgentPlayer(agentId interface{}, multiOrm ...orm.Ormer) int64 {
	start, end := GetTodayTimestamp()
	sql := fmt.Sprintf(`
		SELECT
			COUNT(1)
		FROM
			%v
		WHERE
			agent_uid = %v AND player_uid != 0  AND activate_time >= %v AND activate_time < %v
	`, TableAgentPlayer, agentId, start, end)
	var count int64
	o := NewOrm(multiOrm, DBChess)
	o.Raw(sql).QueryRow(&count)
	return count
}

//获取一级代理名下的还不是正式的二级代理列表
func ListManualReviewUser(p ListParams, uid int64, multiOrm ...orm.Ormer) ([]orm.Params, error) {
	where := fmt.Sprintf(" pid = %v AND status < %v", uid, PfFirstTopUpSuccess)
	limit := (p.PageIndex - 1) * p.PageSize
	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %v WHERE %v`, TablePfUser, where)
	var count int64
	var err error
	var user []orm.Params
	o := NewOrm(multiOrm, DBChessPartner)
	o.Raw(sql).QueryRow(&count)
	/*
			1. status 2-未审核，3-已拒绝，4-未激活
			2. 现在需要排序是未审核--->未激活---->已拒绝
			解决方案:
		 	1. 分两部分排序，未审核的，及已拒绝和未激活的做倒序排序
			2. 有分页功能,所以要先计算出未审核的有多个条记录,然后跟limit,及limit+pageSize做比较
			3. 分三种情况:
				1. count <= limit 说明要的数据已经超了未审核的部分，所以直接返回partTwo
				2. count > limit+pageSize,说明要取的数据是在partOne部分，没有超出未审核数据范围
				3. limit < count <= limit+pageSize,说明两部分都有，
				  第一部分是未审核的limit,count
				  第二部分是partTwo的,0,limit+pageSize-count

	*/
	if count <= limit {
		user, err = listPartTwoReviewUser(uid, limit, p.PageSize)
	}
	if count > limit && count <= limit+p.PageSize {
		user1, err := listPartOneReviewUser(uid, limit, count)
		if err != nil {
			return nil, err
		}
		user2, err := listPartTwoReviewUser(uid, 0, limit+p.PageSize-count)
		if err != nil {
			return nil, err
		}
		user = append(user, user1...)
		user = append(user, user2...)
	}
	if count > limit+p.PageSize {
		user, err = listPartOneReviewUser(uid, limit, p.PageSize)
	}
	return user, err
}

type TmpUser struct {
	Uid        int64 `json:"uid"`
	GroupId    int64 `json:"group_id"`
	CreateTime int64 `json:"create_time"`
}

//列出未审核的代理列表
func listPartOneReviewUser(uid, limit, pageSize int64, multiOrm ...orm.Ormer) ([]orm.Params, error) {
	o := NewOrm(multiOrm, DBChessPartner)
	where := fmt.Sprintf(" pid = %v AND status <= %v", uid, BindPhoneSuccess)

	sql := fmt.Sprintf(`
		SELECT
			uid,nickname,status,create_time,head_img_url
		FROM
			%v
		WHERE
			%v
		LIMIT ?,?
		`, TablePfUser, where)
	var user []orm.Params
	_, err := o.Raw(sql, limit, pageSize).Values(&user)
	if CheckNoExist(err) {
		return user, nil
	}
	return user, nil
}

//列出已拒绝及未激活的代理
func listPartTwoReviewUser(uid, limit, pageSize int64, multiOrm ...orm.Ormer) ([]orm.Params, error) {
	o := NewOrm(multiOrm, DBChessPartner)
	where := fmt.Sprintf(" pid = %v AND status >= %v AND status <= %v", uid, PfVerifyNotPass, PfVerifyPass)
	sql := fmt.Sprintf(`
		SELECT
			uid,nickname,status,create_time,head_img_url
		FROM
			%v
		WHERE
			%v
		ORDER BY
			status DESC
		LIMIT ?,?
		`, TablePfUser, where)
	var user []orm.Params
	_, err := o.Raw(sql, limit, pageSize).Values(&user)
	if CheckNoExist(err) {
		return user, nil
	}
	return user, nil
}

//获取一级代理名下的还未审核的二级代理的数量
func StatManualReviewUser(pid int64, multiOrm ...orm.Ormer) (int64, error) {
	//要把绑定了授权码,手机号,及未激活的二级代理列出来检查是否超过24小时
	where := fmt.Sprintf(" pid = %v AND status IN (%v,%v)",
		pid, PfBindPhoneSuccess, PfVerifyPass)
	sql := fmt.Sprintf(`
		SELECT
			uid,group_id,create_time
		FROM
			%v
		WHERE
			%v
	`, TablePfUser, where)
	o := NewOrm(multiOrm, DBChessPartner)
	var tmp []TmpUser
	o.Raw(sql).QueryRows(&tmp)
	for _, v := range tmp {
		HandleAgentStatus(v.CreateTime, v.Uid, pid, v.GroupId, false)
	}

	where = fmt.Sprintf(" pid = %v AND status = %v", pid, PfBindPhoneSuccess)
	sql = fmt.Sprintf(`
		SELECT
			COUNT(1)
		FROM
			%v
		WHERE
			%v
	`, TablePfUser, where)
	var count int64
	o.Raw(sql).QueryRow(&count)
	return count, nil
}

func IsUserExistByPhone(phone string, multiOrm ...orm.Ormer) (int64, error) {
	sql := fmt.Sprintf(`
		SELECT
			uid
		FROM
			%v
		WHERE
			phone = ?
		LIMIT 1
		`, TablePfUser)
	o := NewOrm(multiOrm, DBChessPartner)
	var uid int64
	err := o.Raw(sql, phone).QueryRow(&uid)
	if CheckNoExist(err) {
		return 0, nil
	}
	return uid, err
}

func IsUserExistByOpenID(openId string, multiOrm ...orm.Ormer) (PartnerUser, error) {
	sql := fmt.Sprintf(`
		SELECT
			uid,frozen,login_time,level,status
		FROM
			%v
		WHERE
			open_id = ?
		LIMIT 1
		`, TablePfUser)
	o := NewOrm(multiOrm, DBChessPartner)
	var user PartnerUser
	err := o.Raw(sql, openId).QueryRow(&user)
	if CheckNoExist(err) {
		return user, nil
	}
	return user, err
}

func IsUserExistByUnionID(unionId string, multiOrm ...orm.Ormer) (PartnerUser, error) {
	sql := fmt.Sprintf(`
		SELECT
			uid,level,status
		FROM
			%v
		WHERE
			union_id = ?
		LIMIT 1
		`, TablePfUser)
	o := NewOrm(multiOrm, DBChessPartner)
	var user PartnerUser
	err := o.Raw(sql, unionId).QueryRow(&user)
	if CheckNoExist(err) {
		return user, nil
	}
	return user, err
}

//获取h5方面的公告(已缓存)(不分页,反正数据也不多，直接全部返回)
func ListNotice() ([]H5Notice, error) {
	var gl []H5Notice
	err := GetCache(RedisCache, KeyPfNotice, &gl)
	if err != nil {
		sql := fmt.Sprintf(`
		SELECT
			*
		FROM
			%v
		WHERE
			publish_time <= %v
		`, TableH5Notice, time.Now().Unix())
		o := NewDBOrm(DBChessSysData)
		_, err := o.Raw(sql).QueryRows(&gl)
		if CheckError(err) {
			return gl, err
		}
		//即使为空也缓存，为了减少因为数据库里不存在此数据而步骤与数据库交互,所以是用checkError而不是checkNoExist
		SetCache(RedisCache, KeyPfNotice, gl, CacheExpire) //one day
	}
	return gl, nil
}

//h5公告
func NoticeInfoById(id int64) (*H5Notice, error) {
	var gl H5Notice
	key := fmt.Sprintf("%v%v", KeyPfNoticeId, id)
	err := GetCache(RedisCache, key, &gl)
	if err != nil {
		sql := fmt.Sprintf(`
		SELECT
			*
		FROM
			%v
		WHERE
			id = %v
		`, TableH5Notice, id)
		o := NewDBOrm(DBChessSysData)
		err := o.Raw(sql).QueryRow(&gl)
		if CheckError(err) {
			return &gl, err
		}
		SetCache(RedisCache, key, gl, CacheExpire) //one day
	}
	return &gl, nil
}

//新建h5方面的反馈
func NewFeedback(data map[string]interface{}, multiOrm ...orm.Ormer) (int64, error) {
	o := NewOrm(multiOrm, DBChessPartner)
	values, sql := InsertSql(TablePfFeedback, data)
	result, err := o.Raw(sql, values).Exec()
	if err != nil {
		return 0, err
	}
	return result.LastInsertId()
}

func NewFeedbackUrl(data map[string]interface{}, multiOrm ...orm.Ormer) (int64, error) {
	o := NewOrm(multiOrm, DBChessPartner)
	values, sql := InsertSql(TablePfFeedbackUrl, data)
	result, err := o.Raw(sql, values).Exec()
	if err != nil {
		return 0, err
	}
	return result.LastInsertId()
}

//列出h5用户的反馈记录
func ListFeedbackRecord(p ListParams, uid int64) ([]orm.Params, int64, error) {
	limit := (p.PageIndex - 1) * p.PageSize
	o := NewDBOrm(DBChessPartner)
	sql := fmt.Sprintf(`
			SELECT
				*
			FROM
				%v
			WHERE
				uid = %v
			LIMIT ?,?
		`, TablePfFeedback, uid)
	var data []orm.Params
	_, err := o.Raw(sql, limit, p.PageSize).Values(&data)
	if CheckNoExist(err) {
		return data, 0, nil
	}
	sql = fmt.Sprintf(`
		SELECT
			url
		FROM
			%v
		WHERE
			fid = ?
	`, TablePfFeedbackUrl)
	for _, v := range data {
		var url []string
		o.Raw(sql, v["id"]).QueryRows(&url)
		v["image_url"] = url
	}
	sql = fmt.Sprintf(`SELECT COUNT(1) FROM %v WHERE uid = %v `,
		TablePfFeedback, uid)
	var count int64
	err = o.Raw(sql).QueryRow(&count)
	return data, count, err
}
